#include "polynomial.h"
#include "term.h"

polynomial::polynomial(void)
{
}


polynomial::~polynomial(void)
{	
	clear();
}

void polynomial::clear(void)
{
	if (!poly.empty()) {
		vector<term*>::iterator itr = poly.begin();
		for(; itr != poly.end(); ++itr)
			delete *itr;
		poly.clear();
	}
}

polynomial& operator *(polynomial &p1, polynomial &p2) 
{
	polynomial *mid = new polynomial();
	vector<term*>::iterator itr1 = p1.poly.begin(), itr2;
	for (;itr1 != p1.poly.end(); ++itr1) {
		for (itr2 = p2.poly.begin(); itr2 != p2.poly.end(); ++itr2) {
			term *nt = new term();
			*nt = (*(*itr1)) * (*(*itr2));
			mid->Add(nt);
		}
	}

	return *mid;
}

/*
 * Merge the multiplicative and the modulo operations
 */
polynomial& polynomial::multiModulo(polynomial &p1, unsigned int n, unsigned int r) 
{
	polynomial *mid = new polynomial();
	vector<term*>::iterator itr1 = poly.begin(), itr2;
	for (;itr1 != poly.end(); ++itr1) {
		for (itr2 = p1.poly.begin(); itr2 != p1.poly.end(); ++itr2) {
			term *nt = new term();
			*nt = (*(*itr1)) * (*(*itr2));
			nt->modulo(n, r);
			mid->Add(nt, n);
		}
	}

	return *mid;
}

/*
 * sorry: to be implemented
 */
polynomial& operator % (polynomial &p1, polynomial &p2)
{
	polynomial *mid = new polynomial();
	
	return *mid;
}

/*
 * warning: recently we just modulo (x^r - 1)
 */
polynomial& polynomial::modulo(unsigned int n, unsigned int r)
{
	polynomial *mid = new polynomial();
	vector<term*>::iterator itr1 = poly.begin();
	for (; itr1 != poly.end(); ++itr1) {		
			term *nt = new term();
			nt->coef = (*itr1)->coef % n;
			nt->exp = (*itr1)->exp % r;
			mid->Add(nt, n);
	}

	return *mid;
}

polynomial& polynomial::operator =(polynomial &p1)
{
	poly.assign(p1.poly.begin(), p1.poly.end());
	return *this;
}

void polynomial::Add(term *t)
{
	if (t->coef == 0)
		return;
	vector<term*>::iterator iter = poly.begin();
	for (; iter != poly.end(); ++iter) {
		if ((*iter)->exp == t->exp) {
			(*iter)->coef += t->coef;
			if ((*iter)->coef == 0)
				poly.erase(iter);
			return ;
		} else if ((*iter)->exp < t->exp) {
			poly.insert(iter, t);
			return;
		}
	}
	
	poly.push_back(t);
}

void polynomial::Add(term *t, int n)
{
	if (t->coef == 0)
		return;
	vector<term*>::iterator iter = poly.begin();
	for (; iter != poly.end(); ++iter) {
		if ((*iter)->exp == t->exp) {
			(*iter)->coef += t->coef;
			if ((*iter)->coef == 0) {
				poly.erase(iter);
			} else {
				(*iter)->coef %= n;
			}
			return ;
		} else if ((*iter)->exp < t->exp) {
			poly.insert(iter, t);
			return;
		}
	}
	
	poly.push_back(t);
}

void polynomial::toString(void)
{
	vector<term*>::iterator itr = poly.begin();
	for (; itr != poly.end(); ++itr)
	{
		printf("+%dx^%d", (*itr)->coef, (*itr)->exp);
	}
}

bool operator == (polynomial &p1, polynomial &p2)
{
	if (p2.poly.size() != p1.poly.size()) 
		return false;

	vector<term*>::iterator iter1 = p1.poly.begin(), iter2 = p2.poly.begin();
	for (; iter1 != p1.poly.end(), iter2 != p2.poly.end(); iter1++, iter2++) {
		if (*(*(iter1)) != *(*(iter2)))
			return false;
	}

	return true;
}


int polynomial::length(void)
{
	return poly.size();
}